// 节流：持续触发一个事件，每隔一段时间只会触发一次。

// function userAction() {
//     console.log(1)
// }
// document.onmousemove = userAction
// 如此打印多次1，似乎感觉不到对性能的影响，如果做了一系列IO操作则会使用户体验感降低很多。
// 根据节流的特点写出第一版节流方案
// (使用时间戳)
function throttle(fun, wait) {
    let previous = 0    // 初始化时时间戳为0，表示第一次执行
    return function() {
        let ctx = this
        let arg = arguments
        let nowTime = new Date().valueOf()  // 当前时间
        if (nowTime - previous >= wait) {   // 当前时间如果距离上一次执行时间大于wait则执行
            fun.apply(ctx, arg)     // 绑定this，传递参数
            previous = nowTime      // 把执行时间改为当前。
        }
    }
}
// (使用定时器)
function throttle(fun, wait) {
    let timer
    return function() {
        let arg = arguments
        let ctx = this
        if (!timer) {
            timer = setTimeout(() => {
                timer = ''
                fun.apply(ctx, arguments)
            }, wait)
        }
    }
}

function userAction(e) {
    console.group()
    console.log(this)
    console.log(e)
    console.groupEnd()
}
// document.onmousemove = throttle(userAction, 1000)
// 时间戳效果，鼠标滑动，立即执行一次，每隔一秒再执行一次，如果在wait期间停止滑动则后续不再触发。
// 定时器效果，鼠标滑动，不会立即执行，而是隔一段时间再执行，在wait期间停止滑动，wait结束后会触发最后一次。

// 结合两种节流的优点，写一个合并版节流函数，第一次立即执行，然后每隔一段时间执行，停止触发后再执行一次
function throttle(fun, wait) {
    let previous = 0
    let timer
    return function() {
        let arg = arguments
        let ctx = this
        let nowTime = new Date().valueOf()
        if (nowTime - previous > wait) {    //当前时间距离上一次执行大于等待时间
            if (timer) {    //如果有延时器在运行则清掉。
                clearTimeout(timer)
                timer = ''
            }
            previous = nowTime  //记录本次执行时间
            fun.apply(ctx, arg)
        } else {    //当前时间距离上一次执行不足wait时间，(wait时触发)
            // 重复触发，更新延时器
            clearTimeout(timer)
            timer = setTimeout(() => {
                previous = nowTime
                timer = ''
                fun.apply(ctx, arg)
            }, wait - (nowTime - previous)) //延迟到下一次整点。
        }
    }
}
// document.onmousemove = throttle(userAction, 1000)
// 鼠标移入立即触发，每1秒执行一次，鼠标停止后，下一次整秒自动触发。

// 产品经理说要再加一个参数😂，用户可以禁用第一次触发或者禁用最后一次触发。
// 那就加一个option参数，first: false和last: false分别代表禁用第一次和最后一次触发。

function throttle(fun, wait, option) {
    let timer
    let previous = 0
    option = option || {}
    return function() {
        let arg = arguments
        let ctx = this
        let nowTime = new Date().valueOf()
        if (!previous && option.first === false) {  // 第一次不执行
            previous = nowTime
        }
        if (nowTime - previous > wait) {
            if (timer) {
                clearTimeout(timer)
                timer = ''
            }
            fun.apply(ctx, arg)
            previous = nowTime
        } else {
            if (option.last !== false) {    // 不设置延时器。
                clearTimeout(timer)
                timer = setTimeout(() => {
                    fun.apply(ctx, arg)
                    previous = nowTime
                    timer = ''
                }, wait - (nowTime - previous))
            }
        }
    }
}
document.onmousemove = throttle(userAction, 1000, {
    first: false,
    // last: false,
})

// 增加取消节流，让下一次立即触发。也是最终代码。
function throttle(fun, wait, option) {
    let timer
    let previous = 0
    option = option || {}
    let throttled =  function() {
        let arg = arguments
        let ctx = this
        let nowTime = new Date().valueOf()
        if (!previous && option.first === false) {  // 第一次不执行
            previous = nowTime
        }
        if (nowTime - previous > wait) {
            if (timer) {
                clearTimeout(timer)
                timer = ''
            }
            fun.apply(ctx, arg)
            previous = nowTime
        } else {
            if (option.last !== false) {    // 不设置延时器。
                clearTimeout(timer)
                timer = setTimeout(() => {
                    fun.apply(ctx, arg)
                    previous = nowTime
                    timer = ''
                }, wait - (nowTime - previous))
            }
        }
    }
    throttled.cancel = function() {
        clearTimeout(timer)
        timer = ''
        previous = ''
    }
    return throttled
}